﻿#pragma once

#include "common.h"
#include <memory>
#include <stack>
#include "texture.h"
#include "transform.h"

namespace anip
{
	// Represents a render buffer, or renderable target, in OpenGL. Apart
	// from methods to transfer data between render buffers, textures and
	// RAM, it also provides a transform context that can be pushed or
	// poped, accessible by drawing functionalities. Note that the method
	// `transformMatrix()` always combines the transform with a conversion
	// from anip's pixel space to OpenGL's clip space. `beginRender()` and
	// `endRender()` are used for calculating frame rate.
	class RenderBuffer : public GLObject
	{
		friend class Context;

	private:
		struct Impl;
		std::unique_ptr<Impl> _pimpl;

		void _setSize(int w, int h);
		const Transform2D& _baseTransform() const;
		
		RenderBuffer();

	public:
		RenderBuffer(int w, int h, int samples = 0);
		RenderBuffer(int w, int h, const TextureOptions& options);
		RenderBuffer(Texture2D& tex);
		RenderBuffer(const RenderBuffer& obj) = delete;

		~RenderBuffer();

		bool success() const;
		unsigned int id() const override;
		const Texture2D& getTexture() const;
		int width() const;
		int height() const;
		vec2 size() const;

		mat3 transformMatrix() const;
		Transform2D transform() const;
		void transformReset();
		void transformPush(const Transform2D& t);
		void transformPushCombined(const Transform2D& t);
		void transformPop();

		void beginRender();
		void endRender() const;

		void blitTo(const RenderBuffer& other) const;
		void blitTo(const RenderBuffer& other,
			int x1, int y1, int w1, int h1, 
			int x2, int y2, int w2, int h2, bool filter = true) const;

		void copyTo(const Texture2D& tex) const;
		void copyTo(const Texture2D& tex, 
			int x1, int y1, int x2, int y2, int w, int h) const;

		// ANIP_TODO: merge with destructor?
		void finalize() override;

		unsigned char* readData() const;
		unsigned char* readData(int x, int y, int w, int h) const;

		void readDataTo(unsigned char* data) const;
		void readDataTo(int x, int y, int w, int h, unsigned char* data) const;
	};
}